﻿#include <iostream>
#include "BaseballPlayer.h"
#include "Employee.h"
#include "Supervisor.h"
#include "PAll.h"
#include "Deried.h"
#include "Animal.h"



void report(Animal& animal)
{
	std::cout << animal.getName() << " says " << animal.speak() << '\n';
	std::cout << animal.getName2() << " says " << animal.speak() << '\n';
}


int main()
{
	std::cout << "Hello World!\n";

	//创建继承类对象
	BaseballPlayer jp{};
	jp.m_name = "jack";
	jp.m_age = 29;
	jp.m_homeRuns = 33;
	jp.m_battingAverage = 23.56;
	jp.print();

	Employee ey{};
	ey.m_name = "sdfsfsd";
	ey.m_age = 23;
	std::cout << ey.m_name << "," << ey.m_age << "\n";

	Supervisor sr{};
	sr.m_name = "二级派生类";
	sr.m_hourlySalary = 90.89;
	std::cout << sr.m_name << "," << sr.m_hourlySalary << "\n";



	//当派生类被销毁时，每个析构函数都以与构造相反的顺序调用。
	//在上面的例子中，当c被销毁时，首先调用c析构函数，然后调用B析构函数和A析构函数。

	//构造派生类时，派生类构造函数负责确定调用哪个基类构造函数。
	//如果未指定基类构造函数，则将使用默认的基类构造函数。
	//在这种情况下，如果找不到默认基类构造函数，编译器将提示错误。
	//然后，按照从最初的基类到最终的派生类执行构造。


	//使用多继承类
	PAll p{};


	//指向派生对象的基类指针和引用
	Person* pr{ &jp };
	std::cout << pr->getName() << "\n";


	//父类指向子类，然后调用父类方法
	Deried dd{};
	//因为base是一个Base引用，所以它调用Base::getName()，
	// 即使它实际上引用了Derived对象的Base部分。
	Base* base{ &dd };
	std::cout << base->getName() << "\n";


	//虚函数是一种特殊类型的成员函数，当被调用时，
	//它解析为被引用或指向的对象的实际类型函数的最底层派生版本。

	//如果派生函数具有与函数的基类版本相同的签名（名称、参数类型以及是否为const）和返回类型，
	//则认为它是匹配的。这些行为称为「覆盖」。
	//要使函数虚拟化，只需将“virtual”关键字放在函数声明之前。

	//调用虚函数方法，实际执行的是子类的方法 getName2
	std::cout << base->getName2() << "\n";


	//多态性是指一个实体具有多种形式的能力（术语“多态性”字面意思是“多种形式”）
	//「编译时多态」是指编译器解析的多态形式。这些包括函数重写解析和模板解析。
	//「运行时多态」是指在运行时解析的多态形式。这包括虚函数解析。
	Cat cat{ "Fred" };
	Dog dog{ "Garbo" };
	report(cat);
	report(dog);



	//不要从构造函数或析构函数调用虚函数
	//创建派生类时，首先构造Base部分。如果你从Base构造函数调用一个虚拟函数，而类的Derived部分甚至还没有创建，
	//它将无法调用该函数的Derived版本，因为Derived函数没有Derived对象部分可供处理。在C++中，它将调用Base版本。


	//虚函数的缺点
	//效率低下——解析虚拟函数调用比解析常规函数调用需要更长的时间。
	//此外，编译器还必须为每个具有一个或多个虚函数的类对象分配一个额外的指针。







}
